package com.pfsbuilder;

import java.awt.Dimension;
import java.awt.Toolkit;
import java.io.File;
import java.io.InputStream;
import java.util.Date;
import java.util.Random;

import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;

import com.pfsbuilder.algorithm.PFSReadImageAlgorithm;
import com.pfsbuilder.fuse.FuseStub;

public class PFSBuilder {
	boolean packFrame = false;
	static boolean isCompress = false;
	static boolean isDecompress = false;
	static boolean havePartitionOffset = false;
	public static CommandLine cmd;

	public PFSBuilder() {
		MainFrame frame = new MainFrame();

		if (packFrame) {
			frame.pack();
		} else {
			frame.validate();
		}

		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		frame.setSize(screenSize.width * 2 / 3, screenSize.height * 2 / 3);
		CommonLib.centerDialog(frame);
		frame.setVisible(true);
	}

	public static void main(String[] args) {
		com.pfsbuilder.Global.sessionNumber = new Random().nextInt();

		CommandLineParser parser = new DefaultParser();
		Options options = new Options();
		try {
			options.addOption("v", "version", false, "display version info");
			options.addOption("projectfile", true, "set the project.ini filename");
			options.addOption("inputdirectory", true, "compress this directory into fs image");
			options.addOption("outputdirectory", true, "extract all files or directories from fs image to this directory");
			options.addOption("output", true, "fs image file");
			options.addOption("input", true, "fs image file");
			options.addOption("partitionsize", true, "partiton size, e.g.: 2KB, 10MB, 2GB, C,H,S");
			options.addOption("partitionoffset", true, "partition offset, e.g.: 2KB, 10MB, 2GB, C,H,S");
			options.addOption("trimto", true, "trim the final output image to the exact size, e.g.: 2KB, 10MB, 2GB, C,H,S");
			options.addOption("blocksize", true, "block size, e.g.: 2KB, 10MB, 2GB");
			options.addOption("partitionname", true, "partition name");
			options.addOption("bufferSize", true, "buffer size");
			options.addOption("gui", false, "show graphical user interface");
			options.addOption("stop", false, "stop the program when exception occurs");
			options.addOption("changes", false, "compress");
			options.addOption("c", false, "compress");
			options.addOption("x", false, "extract");
			options.addOption("fuse_readdir", true, "list file or directory from path");
			options.addOption("fuse_lookup", true, "lookup the block number from path");
			options.addOption("fuse_readFileContent", true, "read file content");
			cmd = parser.parse(options, args);
		} catch (ParseException e1) {
			e1.printStackTrace();
			System.exit(0);
		}

		if (args.length == 0 || cmd.hasOption("version") || cmd.hasOption("v")) {
			System.out.println("Author : Peter Cheung (mcheung63@hotmail.com)");
			System.out.println("Version : " + PropertyUtil.getProperty("version"));
			System.out.println();
			HelpFormatter formatter = new HelpFormatter();
			formatter.printHelp("java -jar PFSBuilder.jar [OPTION]", options);
			System.exit(0);
		}

		if (cmd.hasOption("projectfile")) {
			PFSSettingConstants.projectFile = cmd.getOptionValue("projectfile");
		}
		if (cmd.hasOption("inputdirectory")) {
			PFSSettingConstants.tempDirectory = cmd.getOptionValue("inputdirectory");
		}
		if (cmd.hasOption("outputdirectory")) {
			PFSSettingConstants.tempDirectory = cmd.getOptionValue("outputdirectory");
		}
		if (cmd.hasOption("output")) {
			PFSSettingConstants.filename = cmd.getOptionValue("output");
		}
		if (cmd.hasOption("input")) {
			PFSSettingConstants.filename = cmd.getOptionValue("input");
		}
		if (cmd.hasOption("partitionsize")) {
			long partitionSize = -1;
			if (cmd.getOptionValue("partitionsize").contains(",")) {
				String chsArr[] = cmd.getOptionValue("partitionsize").split(",");

				partitionSize = Long.parseLong(chsArr[0]) * Long.parseLong(chsArr[1]) * Long.parseLong(chsArr[2]) * 512;
			} else {
				partitionSize = CommonLib.convertFilesize(cmd.getOptionValue("partitionsize"));
			}
			if (partitionSize == -1) {
				System.out.println("-partitionsize number error : " + partitionSize);
				return;
			} else if (partitionSize <= 0) {
				System.out.println("partition size too small");
			} else {
				PFSSettingConstants.partitionSize = partitionSize;
			}
		}
		if (cmd.hasOption("partitionoffset")) {
			long partitionOffset = -1;
			if (cmd.getOptionValue("partitionoffset").contains(",")) {
				String chsArr[] = cmd.getOptionValue("partitionoffset").split(",");

				partitionOffset = Long.parseLong(chsArr[0]) * Long.parseLong(chsArr[1]) * Long.parseLong(chsArr[2]) * 512;
			} else {
				partitionOffset = CommonLib.convertFilesize(cmd.getOptionValue("partitionoffset"));
			}
			if (partitionOffset == -1) {
				System.out.println("-partitionoffset number error : " + partitionOffset);
				return;
			} else if (partitionOffset < 0) {
				System.out.println("partition offset cannot be negative");
				return;
			} else {
				PFSSettingConstants.partitionOffset = partitionOffset;
			}
			havePartitionOffset = true;
		}
		if (cmd.hasOption("trimto")) {
			long trimto = -1;
			if (cmd.getOptionValue("trimto").contains(",")) {
				String chsArr[] = cmd.getOptionValue("trimto").split(",");

				trimto = Long.parseLong(chsArr[0]) * Long.parseLong(chsArr[1]) * Long.parseLong(chsArr[2]) * 512;
			} else {
				trimto = CommonLib.convertFilesize(cmd.getOptionValue("trimto"));
			}
			if (trimto == -1) {
				System.out.println("-trimto number error : " + trimto);
				return;
			} else if (trimto < 0) {
				System.out.println("trim to size cannot be negative");
				return;
			} else {
				PFSSettingConstants.trimto = trimto;
			}
			havePartitionOffset = true;
		}
		if (cmd.hasOption("blocksize")) {
			PFSSettingConstants.blockSize = (int) CommonLib.convertFilesize(cmd.getOptionValue("blocksize"));
		}
		if (cmd.hasOption("partitionname")) {
			PFSSettingConstants.partitionName = cmd.getOptionValue("partitionname");
		}
		if (cmd.hasOption("bufferSize")) {
			PFSSettingConstants.bufferSize = Integer.parseInt(cmd.getOptionValue("bufferSize"));
		}
		if (cmd.hasOption("gui")) {
			com.pfsbuilder.Global.GUI = true;
		}
		if (cmd.hasOption("stop")) {
			com.pfsbuilder.Global.stopWhenException = true;
		}
		if (cmd.hasOption("changes")) {
			try {
				InputStream is = com.pfsbuilder.AboutBox.class.getResourceAsStream("changes.txt");
				byte b[] = new byte[1];

				while (is.read(b) != -1) {
					System.out.print(new String(b));
				}
				is.close();
			} catch (Exception ex) {
				System.out.println("changes.txt not found !!!");
			}
		}
		if (cmd.hasOption("c")) {
			isCompress = true;
		}
		if (cmd.hasOption("x")) {
			isDecompress = true;
		}
		if (cmd.hasOption("fuse_readdir")) {
			String path = cmd.getOptionValue("fuse_readdir");
			FuseStub.readdir(path);
			System.exit(0);
		}
		if (cmd.hasOption("fuse_lookup")) {
			String path = cmd.getOptionValue("fuse_lookup");
			System.out.println(path);
			long blockNo = FuseStub.getBlockNo(path);
			System.out.println("blockNo=" + blockNo);
			System.out.println("blockNo=" + FuseStub.isFile(path));
			System.exit(0);
		}
		if (cmd.hasOption("fuse_readFileContent")) {
			String path = cmd.getOptionValue("fuse_readFileContent");
			System.out.println(path);
			long blockNo = FuseStub.getBlockNo(path);
			String content = FuseStub.readFileContent(blockNo);
			System.out.println(content);
			System.exit(0);
		}

		if (com.pfsbuilder.Global.GUI) {
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					try {
						UIManager.setLookAndFeel("com.peterswing.white.PeterSwingWhiteLookAndFeel");
					} catch (Exception e) {
						e.printStackTrace();
					}
					new PFSBuilder();
				}
			});
		} else {
			boolean error = false;
			if (isCompress) {
				if (PFSSettingConstants.projectFile == null) {
					System.out.println("you need -projectfile <file>");
					error = true;
				}
				if (PFSSettingConstants.tempDirectory == null) {
					System.out.println("you need -inputdirectory <input directory>");
					error = true;
				}
				if (PFSSettingConstants.partitionName == null) {
					System.out.println("you need -partitionname <partition name>");
					error = true;
				}
				if (PFSSettingConstants.filename == null) {
					System.out.println("you need -output <file>");
					error = true;
				}
				if (isCompress && isDecompress) {
					System.out.println("-c and -x option cannot coexist");
					error = true;
				}
			}
			if (isDecompress) {
				if (PFSSettingConstants.projectFile == null) {
					System.out.println("you need -projectfile <file>");
					error = true;
				}
				if (PFSSettingConstants.tempDirectory == null) {
					System.out.println("you need -outputdirectory <output directory>");
					error = true;
				}
				if (PFSSettingConstants.filename == null) {
					System.out.println("you need -output <file>");
					error = true;
				}
				if (!havePartitionOffset) {
					System.out.println("you need -partitionOffset <partition offset>");
					error = true;
				}
			}

			if (!isCompress && !isDecompress) {
				System.out.println("You need either -c or -x option");
				error = true;
			}

			if (error) {
				System.exit(0);
			}

			if (!new File(PFSSettingConstants.tempDirectory).exists() && isCompress) {
				System.out.println("directory : " + PFSSettingConstants.tempDirectory + " not exist !!!");
				return;
			}
			if (PFSSettingConstants.blockSize == 0 && isCompress) {
				System.out.println("blocksize not correct, please provide -blocksize command line parameter !!!");
				return;
			}
			if (PFSSettingConstants.partitionSize == 0 && isCompress) {
				System.out.println("partitionSize not correct, please provide -partitionsize command line parameter !!!");
				return;
			}

			if (isCompress) {
				Date startTime = new Date();
				new PFSWriteImageAlgorithm().createPFS(new File(PFSSettingConstants.tempDirectory));
				Date endTime = new Date();
				CommonLib.printSecond((endTime.getTime() - startTime.getTime()) / 1000);
			}
			if (isDecompress) {
				Date startTime = new Date();
				PFSImageConstants.partitionOffset = PFSSettingConstants.partitionOffset;
				new PFSReadImageAlgorithm().readPFS();
				Date endTime = new Date();
				CommonLib.printSecond((endTime.getTime() - startTime.getTime()) / 1000);
			}
		}
	}
}
